/*
 *  doctorOffice.c
 *  
 *
 *  Project part 3
 *
 */

/* You can use the functions defined in the following files .
 * You cannot use // to make comment because this is a c file.
 */
#include "syscall.h"
#include "userlib.h"

/* Constant values*/
#define MAX_NUM_DOCTORS 3
#define MAX_NUM_NURSES 5
#define MAX_NUM_XTECH 2
#define MAX_NUM_IMAGE 3
#define MAX_NUM_ROOMS 5
#define MAX_NUM_PATIENT 100
#define MAX_NUM_CHILD 50

typedef struct SheetEntry {
	int id;
	int doctorId;
	int examineRoomId;
	int patientSymptom; 
	int state;
	int imageNum;
	int xrayResults[MAX_NUM_IMAGE];
	int shotOrNot;
} SheetEntry;

int startSign;
int test;
int childNum;
int totalPatientNum;
int currentxRayLock;
int currentxRay;
int currentDocLock;
int currentDoc;
int currentNurseLock;
int currentNurse;
int currentPatientLock;
int currentPatient;
int currentChildLock;
int currentChild;

/*variables for examine room*/
int examineRoom[MAX_NUM_ROOMS];/* 1 = NOT_USE, 2 = IN_USE, 3 = NOT_EXIST*/
int wallPocketLock;
struct SheetEntry *wallPocket[MAX_NUM_ROOMS];
int examineRoomPatientLock[MAX_NUM_ROOMS];
int examineRoomPatientCV[MAX_NUM_ROOMS];
int doctorInRoom[MAX_NUM_ROOMS];

/*waiting room nurse*/
int wrnLineLock;
int wrnLineCV;
int wrnLineNum;
int wrnState;/* 1 = AVAILABLE, 2 = UNAVAILABLE, 3 = noExist*/
int wrnLock;
int wrnCV;
int patientAge;
int wrnAction;/* 1 = GIVE_FORM, 2 = ACCEPT_FORM, 3 = GIVE_SHEET, 4 = NO_ACTION*/
int patientIdWithWRN;
int nurseIdWithWRN;
struct MyQueue wrnList;

/*doctor*/
int doctorLock[MAX_NUM_DOCTORS];
int doctorState[MAX_NUM_DOCTORS]; /* 1 = AVAILABLE, 2 = UNAVAILABLE, 3 = noExist*/ 
int doctorCV[MAX_NUM_DOCTORS];
int doctorGoRoomId[MAX_NUM_DOCTORS];
struct SheetEntry *sheetForDoctor[MAX_NUM_DOCTORS];

/*patient*/
int patientLock[MAX_NUM_PATIENT];
int patientCV[MAX_NUM_PATIENT];
int xtIdWithPatient[MAX_NUM_PATIENT];
int patientWithNurse[MAX_NUM_PATIENT];
int patientneedto[MAX_NUM_PATIENT];/* 1 = NEED_EXAMINE, 2 = FINE, 3 = NEED_XRAY, 4 = NEED_SHOT, 5 = XRAY_DONE, 6 = DONE;*/
int symptomResponse[MAX_NUM_PATIENT];/* 1 = PAIN, 2 = NAUSEA, 3 = ALIEN_VOICIES*/
int roomId[MAX_NUM_PATIENT];
struct SheetEntry patientSheets[MAX_NUM_PATIENT];
int isChild[MAX_NUM_PATIENT];

/*child*/
int childLock[MAX_NUM_CHILD];
int childCV[MAX_NUM_CHILD];
int childAction[MAX_NUM_CHILD];/* 1 = FOLLOW, 2 = LEAVE, 3 = XRAY, 4 = SHOT*/

/*cashier*/
int cashierLineLock;
int cashierLineCV;
int cashierLock;
int cashierCV;
int cashierLineNum;
int cashierState;/* 1 = AVAILABLE, 2 = UNAVAILABLE, 3 = noExist*/ 
struct MyQueue cashierList;
int cashierListLock;
int finalMoney[MAX_NUM_PATIENT];

/*xray-technician*/
struct MyQueue xrayFinishList;
struct MyQueue xrayWaitList[MAX_NUM_XTECH];
int xRayTechNum;
int xRayWaitLineLock[MAX_NUM_XTECH];
int xRayWaitLineCV[MAX_NUM_XTECH];
int xRayWaitLineNum[MAX_NUM_XTECH];
int xRayLock[MAX_NUM_XTECH];
int xRayCV[MAX_NUM_XTECH];
int xtechnicianstate[MAX_NUM_XTECH]; /* 1 = AVAILABLE, 2 = UNAVAILABLE, 3 = noExist*/
int xtImageNum[MAX_NUM_XTECH];
int waitListLock[MAX_NUM_XTECH];
int finishListLock;

/*nurse*/
int totalNurseNum;
int patientWaitNum;
int cabinetLock;
int nurseDoctorLock;
int nurseWrnLineCV;
int nurseWrnCount;
struct SheetEntry *sheetForNurse[MAX_NUM_NURSES];

/*adult patient*/
int rand;


/* Functions
 Take rand time to do tasks*/
void doTask() {
	int i;
	int time = ++rand%20+10;
	for (i=0; i<time; i++) {
		Yield();
	}
}

void wait(int number) {
	int i;
	for (i=0; i<number; i++) {
		Yield();
	}
}

void GetForm(int index) {
	int arg[1];
	arg[0] = index;
	AcquireLock(wrnLineLock);	/* Acquire the lock*/
	if (wrnState == 2) {
		/* There are some one before me
		 Increase the number in the line, and wait for my turn*/
		wrnLineNum ++;
		if(test==2 || test==7){
			if (index < childNum){
			  myprintf("Parent[%d] gets in line of the Waiting Room Nurse to get registration form.\n", arg, 1);
		  }
		  else
		  	myprintf("Adult Patient [%d] gets in line of the Waiting Room Nurse to get registration form.\n", arg, 1);
		}
		WaitCondition(wrnLineCV, wrnLineLock);
	}else {
		wrnState = 2;
	}
	AcquireLock(wrnLock);
	ReleaseLock(wrnLineLock);
	/* Now there is nobody in line. Waiting room nurse is available
	 Talk to her directly*/
	wrnAction = 1;	/* Get the form*/
	patientIdWithWRN = index;
	SignalCondition(wrnCV, wrnLock);	/* Wake up the waiting room nurse*/
	WaitCondition(wrnCV, wrnLock);	/* Wait for the form*/
	/* Get the form, go to fill the form*/
	if(test==2 || test==7){
		if (index < childNum){
			myprintf("Parent of child patient[%d] gets the form from the Waiting Room Nurse.\n", arg, 1);
	  }
	  else
	  	myprintf("Adult patient [%d] get the form from the Waiting Room Nurse.\n", arg, 1);
	}
	SignalCondition(wrnCV, wrnLock);	/* Signal the waiting room nurse that I am leaving to fill the form*/
	ReleaseLock(wrnLock);	/* Release the lock and go somewhere*/
}

/* Patient submits form to waiting room nurse*/
void SubmitForm(int index) {
	int arg[1];
	arg[0] = index;
	AcquireLock(wrnLineLock);	/* Acquire the lock*/
	if (wrnState == 2) {
		/* There are some one before me
		 Increase the number in the line, and wait for my turn*/
		wrnLineNum ++;
		if(test==2 || test==7){
			if (index < childNum){
				myprintf("Parent[%d] gets in line of the Waiting Room Nurse to submit registration form.\n", arg, 1);
		  }
		  else
		  	myprintf("Adult Patient [%d] gets in line of the Waiting Room Nurse to submit registration form.\n", arg, 1);
		}
		WaitCondition(wrnLineCV, wrnLineLock);
	}else {
		wrnState = 2;
	}
	AcquireLock(wrnLock);
	ReleaseLock(wrnLineLock);
	/* Now there is nobody in line. Waiting room nurse is available
	 Talk to her directly*/
	wrnAction = 2;	/* Submit the form*/
	patientIdWithWRN = index;
	if(test==2 || test==7){
		if (index < childNum){
			patientAge = 1+(++rand)%18;
			myprintf("Parent of child patient[%d] submits the filled form to the Waiting Room Nurse.\n", arg, 1);
	  }
	  else{
	  	patientAge = 18+(++rand)%62;
	  	myprintf("Adult patient [%d] submit the filled form to the Waiting Room Nurse.\n", arg, 1);
	  }
	}
	SignalCondition(wrnCV, wrnLock);	/* Wake up the waiting room nurse*/
	WaitCondition(wrnCV, wrnLock);	/* Wait for the examination sheet*/
	/* Get the sheet, wait for the nurse*/
	SignalCondition(wrnCV, wrnLock);	/* Signal the waiting room nurse that I am leaving to wait the nurse*/
	AcquireLock(patientLock[index]);	/* Make patient wait for nurse first*/
	ReleaseLock(wrnLock);	/* Release the lock and wait for the nurse*/
	if(test==1||test==2||test==7||test==4)
    myprintf("Parent [%d] waits for a Nurse to escort them to the Xray room.\n", arg, 1);
	WaitCondition(patientCV[index], patientLock[index]);
}


void GoToExamineRoom(int index) {
	/* Follow the nurse*/
	int myRoomId = roomId[index];
	int arg1[1];
	int arg2[2];
	int arg3[3];
	arg1[0] = index;
	arg2[0] = index;
	arg3[0] = index;
	arg2[1] = myRoomId;
	arg3[1] = patientWithNurse[index];
	arg3[2] = myRoomId;
	if (index < childNum){
		childAction[index] = 1;
        AcquireLock(childLock[index]);
        SignalCondition(childCV[index], childLock[index]);
        WaitCondition(childCV[index], childLock[index]);
        ReleaseLock(childLock[index]);
	}
	if(test==2 || test==7 || test==1 || test==4 || test==5){
		if (index >= childNum){
			myprintf("Adult Patient [%d] is following Nurse [%d] to Examination Room [%d].\n", arg3, 3);
    }
	}
	if(test==1||test==4||test==7||test==2){
		if (index < childNum){
        myprintf("Parent[%d] is following Nurse[%d] to Examination Room[%d].\n", arg3, 3);
	  }
  }
	SignalCondition(patientCV[index], patientLock[index]);
	WaitCondition(patientCV[index], patientLock[index]);
	if(test==2 || test==7 || test==1 || test==4 || test==5){
		if (index >= childNum){
			myprintf("Adult Patient [%d] has arrived at Examination Room [%d].\n", arg2, 2);
	  }
	}
	if(test==1||test==4||test==7||test==2){
		if (index < childNum){
       myprintf("Parent[%d] has arrived at Examination Room [%d].\n", arg2, 2);
	  }
	}
	/* Get into the examine room and interact with nurse*/
	SignalCondition(patientCV[index], patientLock[index]);
	WaitCondition(patientCV[index], patientLock[index]);
	symptomResponse[index] = ++rand%3;
	switch (symptomResponse[index]) {
		case 1:
			if(test == 7 && index >= childNum)
				myprintf("Adult Patient [%d] says, My symptoms are Pain\n", arg1, 1);
      if((test==1||test==7) && index < childNum)
        myprintf("Parent [%d] says, \"His symptoms are Pain\".\n", arg1, 1);
			break;
		case 2:
			if(test == 7 && index >= childNum)
				myprintf("Adult Patient [%d] says, My symptoms are Nausea\n", arg1, 1);
			if((test==1||test==7) && index < childNum)
				myprintf("Parent [%d] says, \"His symptoms are Nausea\".\n", arg1, 1);
			break;
		case 3:
			if(test == 7 && index >= childNum)
				myprintf("Adult Patient [%d] says, My symptoms are Hear Alien Voices\n", arg1, 1);
			if((test==1||test==7) && index < childNum)
				myprintf("Parent [%d] says, \"His symptoms are Hear Alien Voices\".\n", arg1, 1);
			break;
		default:
			break;
	}
	SignalCondition(patientCV[index], patientLock[index]);
	WaitCondition(patientCV[index], patientLock[index]);
	/* Wait for the doctor
	 Make sure the patient will wait for the doctor first*/
	AcquireLock(examineRoomPatientLock[myRoomId]);
	SignalCondition(patientCV[index], patientLock[index]);
	ReleaseLock(patientLock[index]);
	/* Patient wait for the doctor*/
	WaitCondition(examineRoomPatientCV[myRoomId], examineRoomPatientLock[myRoomId]);
}

void BackToExamineRoom(int index) {
	/* Follow the nurse
	 Make sure the patient will wait for the doctor first*/
	if (index < childNum){
		AcquireLock(childLock[index]);
    SignalCondition(childCV[index], childLock[index]);
    WaitCondition(childCV[index], childLock[index]);
    ReleaseLock(childLock[index]);
    SignalCondition(patientCV[index], patientLock[index]);
    WaitCondition(patientCV[index], patientLock[index]);
	}
	AcquireLock(examineRoomPatientLock[roomId[index]]);
	SignalCondition(patientCV[index], patientLock[index]);
	ReleaseLock(patientLock[index]);
	/* Patient wait for the doctor*/
	WaitCondition(examineRoomPatientCV[roomId[index]], examineRoomPatientLock[roomId[index]]);
}

void GetShot(int index) {
	/* Patient is told she need a shot*/
	int myRoomId = roomId[index];
	int arg[1];
	arg[0] = index;
	ReleaseLock(examineRoomPatientLock[myRoomId]);
	AcquireLock(patientLock[index]);
	/* Wait nurse to get the medicine*/
	if(test == 7 && index >= childNum)
		myprintf("Adult Patient [%d] says, \"Yes I am ready for the shot\".\n", arg, 1);
	if((test==1||test==7) && index < childNum )
		myprintf("Parent [%d] says, \"Yes He is ready for the shot\".\n", arg, 1);
	SignalCondition(patientCV[index], patientLock[index]);
	WaitCondition(patientCV[index], patientLock[index]);
	/* The shot is done*/
	if(test==7)
    myprintf("Child patient [%d] has been given a shot.\n", arg, 1);
	SignalCondition(patientCV[index], patientLock[index]);
	AcquireLock(examineRoomPatientLock[myRoomId]);
	ReleaseLock(patientLock[index]);
	/* Wait the nurse to take me to the cashier*/
	WaitCondition(examineRoomPatientCV[myRoomId], examineRoomPatientLock[myRoomId]);
}

void takexRay(int index){
	int roomNum;
	int imageNum;
	int arg[1];
	int i;
	arg[0] = index;
	if((test == 7 || test==4||test==5) && index >= childNum)
        myprintf("Adult Patient [%d] waits for a Nurse to escort them to Xray room.\n", arg, 1);
	if((test==1||test==7||test==4) && index < childNum)
		    myprintf("Parent[%d] waits for a Nurse to escort them to the Xray room.\n",  arg, 1);
	SignalCondition(examineRoomPatientCV[roomId[index]], examineRoomPatientLock[roomId[index]]);
	if (index < childNum){
		childAction[index] = 1;
    AcquireLock(childLock[index]);
    SignalCondition(childCV[index], childLock[index]);
    WaitCondition(childCV[index], childLock[index]);
    ReleaseLock(childLock[index]);
	}
	AcquireLock(patientLock[index]);
	ReleaseLock(examineRoomPatientLock[roomId[index]]);
	WaitCondition(patientCV[index], patientLock[index]);
	/*Patient goes to the waiting room of xray room*/
	roomNum = xtIdWithPatient[index];
	AcquireLock(xRayWaitLineLock[roomNum]);
	SignalCondition(patientCV[index], patientLock[index]);
	ReleaseLock(patientLock[index]);
	if (xtechnicianstate[roomNum] == 2){
		/*there are someone in front of the patient,he has to wait */
		xRayWaitLineNum[roomNum]++;
		WaitCondition(xRayWaitLineCV[roomNum], xRayWaitLineLock[roomNum]);
	}
	else {
		xtechnicianstate[roomNum] = 2;
	}
	ReleaseLock(xRayWaitLineLock[roomNum]);
	AcquireLock(xRayLock[roomNum]);
	SignalCondition(xRayCV[roomNum], xRayLock[roomNum]);
	WaitCondition(xRayCV[roomNum], xRayLock[roomNum]);
	if(test==7){
		if (index >= childNum)
      myprintf("Adult Patient [%d] gets on the table.\n", arg, 1);
    else
    	myprintf("Child Patient [%d] gets on the table.\n", arg, 1);
	}
	SignalCondition(xRayCV[roomNum], xRayLock[roomNum]);
	if(test==7){
		if (index >= childNum)
      myprintf("Adult Patient [%d] has been asked to take an Xray.\n", arg, 1);
	  else
	  	myprintf("Child Patient [%d] has been asked to take an Xray.\n", arg, 1);
	}
	imageNum = xtImageNum[roomNum];
	for (i=0; i<imageNum-1; i++){
		WaitCondition(xRayCV[roomNum], xRayLock[roomNum]);
		if(test==7)
      myprintf("Child Patienht [%d] moves for the next Xray.\n", arg, 1);
		SignalCondition(xRayCV[roomNum], xRayLock[roomNum]);
	}
	WaitCondition(xRayCV[roomNum], xRayLock[roomNum]);
	SignalCondition(xRayCV[roomNum], xRayLock[roomNum]);
	AcquireLock(patientLock[index]);
	ReleaseLock(xRayLock[roomNum]);
	/*patient wait in the finish xray waiting room  */
	WaitCondition(patientCV[index], patientLock[index]);
}

/* Patient interacts with doctor*/
void InteractWithDoctor(int index){
	int arg[2];
	int myRoomId = roomId[index];
	int doctorId = doctorInRoom[myRoomId];
	arg[0] = index;
	arg[1] = doctorId;
	AcquireLock(doctorLock[doctorId]);
	ReleaseLock(examineRoomPatientLock[myRoomId]);
	SignalCondition(doctorCV[doctorId], doctorLock[doctorId]);
	WaitCondition(doctorCV[doctorId], doctorLock[doctorId]);
	if(test==7||test==6){
		if (index >= childNum){
			myprintf("Adult Patient [%d] has been diagnosed by Doctor [%d].\n", arg, 2);
	  }
	  else
	  	myprintf("Child Patient [%d] has been diagnosed by Doctor [%d].\n", arg, 2);
	}
	if (patientneedto[index] == 3){
		if(test==7||test==6){
			if (index >= childNum){
				myprintf("Adult Patient [%d] has been informed by Doctor [%d] that he needs an Xray.\n", arg, 2);
	    }
	    else
	    	myprintf("Child Patient [%d] has been informed by Doctor [%d] that he needs an Xray.\n", arg, 2);
	  }
	}
	if (patientneedto[index] == 4){
		if(test==7||test==6){
			if (index >= childNum){
				myprintf("Adult Patient [%d] has been informed by Doctor [%d] that he will be administered a shot.\n", arg, 2);
	    }
	    else
	    	myprintf("Child Patient [%d] has been informed by Doctor [%d] that he will be administered a shot.\n", arg, 2);
	  }
	}
	SignalCondition(doctorCV[doctorId], doctorLock[doctorId]);
	AcquireLock(examineRoomPatientLock[myRoomId]);
	ReleaseLock(doctorLock[doctorId]);
	WaitCondition(examineRoomPatientCV[myRoomId], examineRoomPatientLock[myRoomId]);
}

/* Patient pays money to the cashier*/
void PayMoney(int index) {
	int arg[2];
	arg[0] = index;
	if (index >= childNum)
	  ReleaseLock(examineRoomPatientLock[roomId[index]]);
	if (index < childNum){
		childAction[index] = 1;
    AcquireLock(childLock[index]);
    SignalCondition(childCV[index], childLock[index]);
    WaitCondition(childCV[index], childLock[index]);
    ReleaseLock(childLock[index]);
    SignalCondition(examineRoomPatientCV[roomId[index]], examineRoomPatientLock[roomId[index]]);
    WaitCondition(examineRoomPatientCV[roomId[index]], examineRoomPatientLock[roomId[index]]);
        
    ReleaseLock(examineRoomPatientLock[roomId[index]]);
	}
	AcquireLock(cashierLineLock);
	if (cashierState != 1) {
		/* The cashier is not available wait in the line*/
		cashierLineNum ++;
		if((test==3||test==7) && index >= childNum)
			myprintf("Adult Patient [%d] enters the queue for Cashier\n", arg, 1);
		if((test==1||test==7||test==3||test==4) && index < childNum)
			myprintf("Parent[%d] enters the queue for Cashier.\n", arg, 1);
		WaitCondition(cashierLineCV, cashierLineLock);
	}else {
		cashierState = 2;
	}
	
	AcquireLock(cashierLock);
	ReleaseLock(cashierLineLock);
	/* If the cashier is available, walk to the cashier*/
	if(test==3||test==7){
		if(index >= childNum){
			myprintf("Adult Patient [%d] reaches the Cashier.\n",  arg, 1);
			myprintf("Adult Patient [%d] hands over his examination sheet to the Cashier.\n", arg, 1);
	  }
	  else{
	  	myprintf("Parent [%d] reaches the Cashier.\n", arg, 1);
      myprintf("Parent [%d] hands over his examination sheet to the Cashier.\n",  arg, 1);
	  }
	}
	/* Wait cashier determine the fee*/
	SignalCondition(cashierCV, cashierLock);
	WaitCondition(cashierCV, cashierLock);
	arg[1] = finalMoney[index];
	if(test==3||test==7){
		if(index >= childNum)
			myprintf("Adult Patient [%d] pays the Cashier $ %d \n", arg, 2);
	  else
	  	myprintf("Parent [%d] pays the Cashier $ %d \n",  arg, 2);
	}
	/* Wait for the receipt*/
	SignalCondition(cashierCV, cashierLock);
	WaitCondition(cashierCV, cashierLock);
	arg[1] = index;
	if(test==3||test==7){
		if(index >= childNum)
			myprintf("Adult Patient [%d] receives a receipt from the Cashier.\n",  arg, 1);
	  else
	  	myprintf("Parent [%d] receives a receipt for Child Patient[%d] from the Cashier.\n", arg, 2);
	}
	SignalCondition(cashierCV, cashierLock);
	if((test==3||test==7||test==5) && index >= childNum)
		myprintf("Adult Patient [%d] leaves the doctor's office.\n", arg, 1);
	if((test==1||test==7||test==3||test==5) && index < childNum)
		myprintf("Parent [%d] leaves the doctor's office with Child Patient[%d].\n", arg, 2);
	totalPatientNum --;
	ReleaseLock(cashierLock);
}

void AdultPatient(){
	int index;
	int patientaction;
	int arg[2];
	AcquireLock(currentPatientLock);
	if(currentPatient == 0) {
		myprintf("I'm the first patient\n", 0, 0);
	}
	if(currentPatient == 3) {
		myprintf("I'm patient No.3 \n", 0, 0);
	}
	index = currentPatient;
	currentPatient++;
	ReleaseLock(currentPatientLock);
	arg[0] = index;
	arg[1] = index;
	while (startSign > 0) {
		/* Check the start signal to see if I can start*/
		wait(5);
	}
	
	/* A patient gets into the office*/
	if(index < childNum){
  myprintf("Child Patient [%d] has entered the Doctor's Office Waiting Room with Parent [%d].\n", arg, 2);
  }
  else{
	myprintf("Adult Patient [%d] has entered the Doctor's Office Waiting Room.\n", arg, 1);
  }
	/* First, he has to interact with the waiting room nurse to get a form*/
	GetForm(index);
	/* The patient fills the form*/
	doTask();
	/* He comes back to the waiting room nurse to submit the form*/
	SubmitForm(index);
	/* The patient is waiting for the nurse to call him*/
	GoToExamineRoom(index);
	InteractWithDoctor(index);
	while (1) {
		patientaction = patientneedto[index];
		if (patientaction == 3){
			takexRay(index);
		}
		else if (patientaction == 4){
			GetShot(index);
		}
		else if (patientaction == 5) {
			BackToExamineRoom(index);
			InteractWithDoctor(index);
		}
		else if (patientaction == 6){
			break;
		}
	}	
	PayMoney(index);
	Exit(0);
}

void ChildPatient() {
	int index;
	int arg[2];
	AcquireLock(currentChildLock);
	index = currentChild++;
	isChild[index] = 1;
	ReleaseLock(currentChildLock);
	arg[0] = index;
	arg[1] = index;
	while (1) {
		AcquireLock(childLock[index]);
		WaitCondition(childCV[index], childLock[index]);
		/* Wait for parent telling them to follow*/
		if (childAction[index] == 1) {
			if(test==1 || test==4||test==7)
				myprintf("Parent[%d] asks Child Patient[%d] to follow them.\n", arg , 2);
			SignalCondition(childCV[index], childLock[index]);
		}else if (childAction[index] == 2) {
			SignalCondition(childCV[index], childLock[index]);
			ReleaseLock(childLock[index]);
			break;
		}
		ReleaseLock(childLock[index]);
	}
	Exit(0);
}


void WaitingRoomNurse() {
	/* Make sure the thread is executed before patient threads*/
	int arg1[1];
	int arg2[2];
	int arg3[2];
	int i;
	int nurseId;
	int patientId;
	while (1) {
		AcquireLock(wrnLineLock);
		/* Check if there are nurses waiting*/
		if (nurseWrnCount == 0 && wrnLineNum == 0) {
			/* No nurse, No patient*/
			wrnState = 1;
		}else if (nurseWrnCount > 0) {
			/* Nurse waiting and there are patients waiting for the nurse
			 Wake up the nurse*/
			SignalCondition(nurseWrnLineCV, wrnLineLock);
			nurseWrnCount --;
			wrnState = 2;
		}else if (wrnLineNum > 0) {
			SignalCondition(wrnLineCV, wrnLineLock);
			wrnLineNum --;  /* Decrease the number of patients in the line*/
			wrnState = 2;
		}
		AcquireLock(wrnLock);
		startSign --;
		ReleaseLock(wrnLineLock);
		WaitCondition(wrnCV, wrnLock);  /* Wait for someone coming*/
		/* Patient comes*/
		switch (wrnAction) {
			case 1:
				patientId = patientIdWithWRN;
				arg1[0] = patientId;
				if (patientId < childNum){
					if(test==7||test==2)
						myprintf("Waiting Room nurse gives a form to the Parent of Child patient [%d].\n", arg1, 1);
				}
				else{
					if(test==7||test==2)
						myprintf("Waiting Room nurse gives a form to Adult patient [%d].\n", arg1, 1);
				}
				SignalCondition(wrnCV, wrnLock);
				WaitCondition(wrnCV, wrnLock);
				ReleaseLock(wrnLock);
				break;
			case 2:
				patientId = patientIdWithWRN;
				arg1[0] = patientId;
				arg2[0] = patientId;
				arg2[1] = patientAge;
				if (patientId < childNum){
					if(test==7||test==2)
						myprintf("Waiting Room nurse accepts the form from Parent with name [%d] and age [%d].\n", arg2, 2);
				}
				else{
					if(test==7||test==2)
						myprintf("Waiting Room nurse accepts the form from Adult Patient with name [%d] and age [%d].\n", arg2, 2);                         
				}
				patientSheets[patientId].id = patientId;
				patientSheets[patientId].state = 1;
				InQueue(&wrnList, &patientSheets[patientId]);
				if (patientId < childNum){
					if(test==7||test==2)
						myprintf("Waiting Room nurse creates an examination sheet for Child patient with name [%d] and age [%d].\n", arg2, 2);
				}
				else{
					if(test==7||test==2)
						myprintf("Waiting Room nurse creates an examination sheet for Adult patient with name [%d] and age [%d].\n", arg2, 2);                              
				}
				if (patientId < childNum){
					if(test==1||test==7||test==2)
						myprintf("Waiting Room nurse tells the Parent [%d] to wait in the waiting room for a nurse.\n",  arg1, 1);
				}
				else{
					if(test==7||test==2)
						myprintf("Waiting Room nurse tells the Adult Patient [%d] to wait in the waiting room for a nurse.\n", arg1, 1);                                
				}
				patientWaitNum ++;
				SignalCondition(wrnCV, wrnLock);
				WaitCondition(wrnCV, wrnLock);
				ReleaseLock(wrnLock);
				break;
			case 3:
				nurseId = nurseIdWithWRN;
				sheetForNurse[nurseId] = (SheetEntry *) DeQueue(&wrnList);
				arg3[0] = sheetForNurse[nurseId]->id;
				arg3[1] = nurseId;
				if(test==7||test==2)
					myprintf("Waiting Room nurse gives examination sheet of patient[%d] to Nurse[%d].\n", arg3, 2);
				SignalCondition(wrnCV, wrnLock);
				WaitCondition(wrnCV, wrnLock);
				ReleaseLock(wrnLock);
				break;
			case 4:
				break;
			default:
				Write("Error: Unkown states in WaitingRoomNurse\n", 32,  ConsoleOutput);
				break;
		}
	}
	Exit(0);
}

/* Find a available examine room*/
int FindExamineRoom() {      
	int found = -1;
	int i;
	AcquireLock(wallPocketLock);
	for (i=0; i<MAX_NUM_ROOMS; i++) {
		if (examineRoom[i] == 1) {
			examineRoom[i] = 2;        /* Occupy the room*/
			found = i;
			break;
		}
	}
	ReleaseLock(wallPocketLock);
	return found;
}

/* Release an examine room*/
void ReleaseExamineRoom(int index) {
	int arg[1];
	arg[0] = index;
	AcquireLock(wallPocketLock);
	if (examineRoom[index] != 3) {
		examineRoom[index] = 1;
	}else {
		myprintf("Error: examine room %d doesn't exist\n", arg, 1);
	}
	ReleaseLock(wallPocketLock);
}

int FindAvailableDoctor() {
	int doctorId = -1;
	int i;
	AcquireLock(nurseDoctorLock);
	for (i=0; i<MAX_NUM_DOCTORS; i++) {
		if (doctorState[i] == 1) {
			doctorId = i;
			doctorState[i] = 2;
			break;
		}
	}
	ReleaseLock(nurseDoctorLock);
	return doctorId;
}

void CallDoctor(int index, int examineRoomId, SheetEntry *myLocalSheet) {
	/* Find an available doctor*/
	int doctorId = FindAvailableDoctor();
	int arg1[3];
	int arg2[4];
	arg1[0] = index;
	arg2[0] = index;
	arg1[1] = doctorId;
	arg2[1] = doctorId;
	arg1[2] = myLocalSheet->id;
	arg2[2] = myLocalSheet->id;
	arg2[3] = examineRoomId;
	if (doctorId >= 0) {
		/* There is an available doctor*/
		AcquireLock(doctorLock[doctorId]);
		/* Tell the doctor which room to go*/
		doctorGoRoomId[doctorId] = examineRoomId;
		/* Wake up the doctor*/
		SignalCondition(doctorCV[doctorId], doctorLock[doctorId]);
		if (myLocalSheet->id < childNum){
			if(test==1||test==7||test==6)
				myprintf("Nurse [%d] informs Doctor [%d] that Child Patient [%d] is waiting in the examination room [%d].\n", arg2, 4);
		}
		else{
			if(test==7||test==6)
				myprintf("Nurse [%d] informs Doctor [%d] that Adult Patient [%d] is waiting in the examination room [%d].\n", arg2, 4);
		}
		/* Give doctor the examine sheet*/
		myLocalSheet->doctorId = doctorId;
		sheetForDoctor[doctorId] = myLocalSheet;
		if (myLocalSheet->id < childNum){
			if(test==7||test==6)
				myprintf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Child Patient [%d].\n", arg1, 3);
		}
		else{
			if(test==7||test==6)
				myprintf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult Patient [%d].\n", arg1, 3);	  	
		}
		ReleaseLock(doctorLock[doctorId]);
	}else {
		/* No doctor available, put the sheet in the wall pocket*/
		AcquireLock(wallPocketLock);
		wallPocket[examineRoomId] = myLocalSheet;
		ReleaseLock(wallPocketLock);
	}
}

void Nurse() {
	/* Make sure the thread is executed before patient threads*/
	int index;
	int doctorId;
	int arg1[1];
	int arg2[2];
	int arg3[3];
	int arg4[4];
	int xtechId;
	int examineRoomId;
	int i;
	struct SheetEntry *myLocalSheet;
	AcquireLock(currentNurseLock);
	index = currentNurse ++;
	ReleaseLock(currentNurseLock);
	arg1[0] = index;
	arg2[0] = index;
	arg3[0] = index;
	arg4[0] = index;
	while (startSign > 0) {
		wait(2);
	}
	while (totalPatientNum > 0) {
		examineRoomId = FindExamineRoom();
		if (examineRoomId >= 0) {
			/* If there is an open examination room
			 Task 1: Get patient from waiting room, escort to exam room
			 Nurse will ask waiting room nurse whether there is any patient waiting for examination*/
			AcquireLock(wrnLineLock);
			if (wrnState == 2) {
				nurseWrnCount ++;
				WaitCondition(nurseWrnLineCV, wrnLineLock);
			}else {
				wrnState = 2;
			}
			if (patientWaitNum > 0) {
				/* There are some patients waiting for examination
				 Waiting room nurse gives the examination sheet to the nurse*/
				patientWaitNum --;
				AcquireLock(wrnLock);
				ReleaseLock(wrnLineLock);
				/* Tell the waiting room nurse to give a sheet*/
				if(test==7||test==2)
					myprintf("Nurse[%d] tells Waiting Room Nurse to give a new examination sheet.\n", arg1, 1);
				nurseIdWithWRN = index;
				wrnAction = 3;
				SignalCondition(wrnCV, wrnLock);
				/*Wait for the sheet*/
				WaitCondition(wrnCV, wrnLock);
				myLocalSheet = sheetForNurse[index];
				arg2[1] = myLocalSheet->id;
				arg3[1] = myLocalSheet->id;
				arg3[2] = examineRoomId;
				SignalCondition(wrnCV, wrnLock);
				AcquireLock(patientLock[myLocalSheet->id]);
				ReleaseLock(wrnLock);
				/* Nurse calls the patient to follow her*/
				roomId[myLocalSheet->id] = examineRoomId;
				patientWithNurse[myLocalSheet->id] = index;
				SignalCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				WaitCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				/* Nurse takes the patient to the examination room*/
				if (myLocalSheet->id < childNum){
					if(test==7||test==1||test==4)
						myprintf("Nurse [%d] escorts Parent [%d] to the examination room [%d].\n", arg3, 3);
				}
				else{
					if(test==7||test==4)
						myprintf("Nurse [%d] escorts Adult Patient [%d] to the examination room [%d].\n", arg3, 3);
				}
				SignalCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				WaitCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				/* Take temperature, blood pressure*/
				if (myLocalSheet->id < childNum){
					if(test==7){
						myprintf("Nurse [%d] takes the temperature and blood pressure of Child [%d].\n", arg2, 2);
						/* Ask sympton*/
						myprintf("Nurse [%d] asks Parent [%d] \"What Symptoms do you have?\"\n", arg2, 2);
					}
				}
				else{
					if(test==7){
						myprintf("Nurse [%d] takes the temperature and blood pressure of Adult Patient [%d].\n", arg2, 2);
						/* Ask sympton*/
						myprintf("Nurse [%d] asks Adult Patient [%d] \"What Symptoms do you have?\"\n", arg2, 2);
					}
				}
				SignalCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				/* Wait for patient's response;*/
				WaitCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				/* Write the sympton on the examine sheet*/
				myLocalSheet->patientSymptom = symptomResponse[myLocalSheet->id];
				if (myLocalSheet->id < childNum){
					if(test==7)
						myprintf("Nurse [%d] writes all the information of Child [%d] in his examination sheet.\n", arg2, 2);
				}
				else{
					if(test==7)
						myprintf("Nurse [%d] writes all the information of Adult Patient [%d] in his examination sheet.\n", arg2, 2);                             
				}
				SignalCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				WaitCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				ReleaseLock(patientLock[myLocalSheet->id]);
				/* Call the doctor*/
				CallDoctor(index, examineRoomId, myLocalSheet);
			}else {
				AcquireLock(wrnLock);
				ReleaseLock(wrnLineLock);
				wrnAction = 4;
				SignalCondition(wrnCV, wrnLock);
				ReleaseLock(wrnLock);
				ReleaseExamineRoom(examineRoomId);
			}
		}
		doTask();
		/* Task 2: Escort patient back to exam room*/
		AcquireLock(finishListLock);
		if (xrayFinishList.number != 0) {
			myLocalSheet = (SheetEntry *)DeQueue(&xrayFinishList);
			arg2[1] = myLocalSheet->id;
			if (myLocalSheet->id < childNum){
				if(test==7||test==1)
					myprintf("Nurse [%d] gets examination sheet for Parent [%d] in Xray waiting room.\n", arg2, 2);
			}
			else{
				if(test==7)
					myprintf("Nurse [%d] gets examination sheet for Adult Patient [%d] in Xray waiting room.\n", arg2, 2);
			}
			myLocalSheet->state = 5;
			ReleaseLock(finishListLock);
			AcquireLock(patientLock[myLocalSheet->id]);
			/* Tell patient back to the examine room*/
			patientneedto[myLocalSheet->id] = 5;
			/*YJ add*/
			examineRoomId = roomId[myLocalSheet->id];
			if (myLocalSheet->id < childNum){
				SignalCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				WaitCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
				arg3[1] = myLocalSheet->id;
				arg3[2] = examineRoomId;
				if(test==7||test==1||test==4)
					myprintf("Nurse [%d] escorts Parent [%d] to the examination room [%d].\n",  arg3, 3);
			}
			else{
				if(test==7||test==4)
					myprintf("Nurse [%d] escorts Adult Patient [%d] to the examination room [%d].\n", arg3, 3);                        
			}
			SignalCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
			WaitCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
			ReleaseLock(patientLock[myLocalSheet->id]);
			/* Call the doctor*/
			doctorId = myLocalSheet->doctorId;
			AcquireLock(nurseDoctorLock);
			if (doctorState[doctorId] == 1) {
				doctorState[doctorId] = 2;
			}else {
				doctorId = -1;
			}
			ReleaseLock(nurseDoctorLock);
			if (doctorId >=0) {
				/* The doctor is available*/
				AcquireLock(doctorLock[doctorId]);
				/* Tell the doctor which room to go*/
				doctorGoRoomId[doctorId] = myLocalSheet->examineRoomId;
				/* Wake up the doctor*/
				SignalCondition(doctorCV[doctorId], doctorLock[doctorId]);
				arg4[1] = doctorId;
				arg4[2] = myLocalSheet->id;
				arg4[3] = myLocalSheet->examineRoomId;
				if (myLocalSheet->id < childNum){
					if(test==7||test==6)
						myprintf("Nurse [%d] informs Doctor [%d] that Child Patient [%d] is waiting in the examination room [%d].\n", arg4, 4);
				}
				else{
					if(test==7||test==6)
						myprintf("Nurse [%d] informs Doctor [%d] that Adult Patient [%d] is waiting in the examination room [%d].\n", arg4, 4);                            
				}
				/* Give doctor the examine sheet*/
				myLocalSheet->doctorId = doctorId;
				sheetForDoctor[doctorId] = myLocalSheet;
				arg3[1] = doctorId;
				arg3[2] = myLocalSheet->id;
				if (myLocalSheet->id < childNum){
					if(test==7||test==6)
						myprintf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Child Patient [%d].\n", arg3, 3);
				}
				else{
					if(test==7||test==6)
						myprintf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult Patient [%d].\n", arg3, 3);                           
				}
				ReleaseLock(doctorLock[doctorId]);
			}else {
				/* The doctor is not available, put the sheet in the wall pocket*/
				AcquireLock(wallPocketLock);
				wallPocket[examineRoomId] = myLocalSheet;
				ReleaseLock(wallPocketLock);
			}
		}else {
			ReleaseLock(finishListLock);
		}
		doTask();
		/* Task 3: Check wall pocket outside the room*/
		examineRoomId = -1;
		AcquireLock(wallPocketLock);
		for (i=0; i<MAX_NUM_ROOMS; i++) {
			if (wallPocket[i] != 0) {
				examineRoomId = i;
				myLocalSheet = wallPocket[i];
				wallPocket[i] = 0;
				break;
			}
		}
		ReleaseLock(wallPocketLock);
		if (examineRoomId >=0 ) {
			/* There is an examine sheet in the wall pocket*/
			arg2[1] = examineRoomId;
			if(test==7||test==4)
				myprintf("Nurse [%d] checks the wall box of examination room[%d]\n", arg2, 2);
			/* Take different actions according to the patient's state in the examination room*/
			switch (myLocalSheet->state) {
				case 3:
					/* Tell patient to follow to take xray*/
					patientneedto[myLocalSheet->id] = 3;
					AcquireLock(examineRoomPatientLock[examineRoomId]);
					SignalCondition(examineRoomPatientCV[examineRoomId], examineRoomPatientLock[examineRoomId]);
					WaitCondition(examineRoomPatientCV[examineRoomId], examineRoomPatientLock[examineRoomId]);
					ReleaseLock(examineRoomPatientLock[examineRoomId]);
					AcquireLock(patientLock[myLocalSheet->id]);
					xtechId = ++rand%xRayTechNum;
					arg3[1] = myLocalSheet->id;
					arg3[2] = xtechId;
					/* Wait the patient
					 Take patient to the Xray Technician*/
					if (myLocalSheet->id < childNum){
						if(test==7||test==1||test==4)
							myprintf("Nurse [%d] escorts Parent [%d] to the X-ray room [%d]\n", arg3, 3);
					}
					else{
						if(test==7||test==4)
							myprintf("Nurse [%d] escorts Adult Patient [%d] to the X-ray room [%d]\n", arg3, 3);                                     
					}
					/* Put the examination sheet in the pocket*/
					myLocalSheet->examineRoomId = examineRoomId;
					AcquireLock(waitListLock[xtechId]);
					if (myLocalSheet->id < childNum){
						if(test==7)
							myprintf("Nurse [%d] informs X-Ray Technician [%d] about Child Patient [%d] and hands over the examination sheet.\n", arg3, 3);
					}
					else{
						if(test==7)
							myprintf("Nurse [%d] informs X-Ray Technician [%d] about Adult Patient [%d] and hands over the examination sheet.\n", arg3, 3);                                          
					}
					InQueue(&xrayWaitList[xtechId], myLocalSheet);
					xtIdWithPatient[myLocalSheet->id] = xtechId;
					SignalCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
					WaitCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
					if(test==7)
						myprintf("Nurse [%d] leaves the X-ray waiting Room.\n", arg1, 1);
					ReleaseLock(patientLock[myLocalSheet->id]);
					ReleaseLock(waitListLock[xtechId]);
					break;
				case 5:
					arg2[1] = myLocalSheet->id;
					doctorId = myLocalSheet->doctorId;
					AcquireLock(nurseDoctorLock);
					if (doctorState[doctorId] == 1) {
						doctorState[doctorId] = 2;
					}else {
						doctorId = -1;
					}
					ReleaseLock(nurseDoctorLock);
					if (doctorId >=0) {
						/* The doctor is available*/
						AcquireLock(doctorLock[doctorId]);
						/* Tell the doctor which room to go*/
						doctorGoRoomId[doctorId] = examineRoomId;
						/* Wake up the doctor*/
						SignalCondition(doctorCV[doctorId], doctorLock[doctorId]);
						arg4[1] = doctorId;
						arg4[2] = myLocalSheet->id;
						arg4[3] = examineRoomId;
						if (myLocalSheet->id < childNum){
							if(test==7||test==6)
								myprintf("Nurse [%d] informs Doctor [%d] that Child Patient [%d] is waiting in the examination room [%d].\n", arg4, 4);
						}
						else{
							if(test==7||test==6)
								myprintf("Nurse [%d] informs Doctor [%d] that Adult Patient [%d] is waiting in the examination room [%d].\n", arg4, 4);                                          
						}
						/* Give doctor the examine sheet*/
						myLocalSheet->doctorId = doctorId;
						sheetForDoctor[doctorId] = myLocalSheet;
						arg3[1] = doctorId;
						arg3[2] = myLocalSheet->id;
						if (myLocalSheet->id < childNum){
							if(test==7||test==6)
								myprintf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Child Patient [%d].\n", arg3, 3);
						}
						else{
							if(test==7||test==6)
								myprintf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult Patient [%d].\n", arg3, 3);                                           
						}
						ReleaseLock(doctorLock[doctorId]);
					}else {
						/* The doctor is not available, put the sheet in the wall pocket*/
						AcquireLock(wallPocketLock);
						wallPocket[examineRoomId] = myLocalSheet;
						ReleaseLock(wallPocketLock);
					}
					break;
				case 1:
					/* Need Doctor*/
					CallDoctor(index, examineRoomId, myLocalSheet);
					break;
				case 4:
					AcquireLock(examineRoomPatientLock[examineRoomId]);
					/* Wake up the patient*/
					SignalCondition(examineRoomPatientCV[examineRoomId], examineRoomPatientLock[examineRoomId]);
					AcquireLock(patientLock[myLocalSheet->id]);
					patientneedto[myLocalSheet->id] = 4;
					ReleaseLock(examineRoomPatientLock[examineRoomId]);
					/* Get medicine*/
					AcquireLock(cabinetLock);
					arg2[1] = myLocalSheet->id;
					if (myLocalSheet->id < childNum){
						if(test==7||test==1)
							myprintf("Nurse [%d] goes to supply cabinet to give to take medicine for Parent [%d].\n", arg2, 2);
					}
					else{
						if(test==7)
							myprintf("Nurse [%d] goes to supply cabinet to give to take medicine for Adult Patient [%d].\n", arg2, 2);                                        
					}
					ReleaseLock(cabinetLock);
					if (myLocalSheet->id < childNum){
						if(test==7||test==1)
							myprintf("Nurse [%d] asks Parent [%d] \"Whether you are ready for the shot?\"\n", arg2, 2);
					}
					else{
						if(test==7)
							myprintf("Nurse [%d] asks Adult Patient [%d] \"Whether you are ready for the shot?\"\n", arg2, 2);                                        
					}
					WaitCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
					/* Shot
					 Shot over*/
					if (myLocalSheet->id < childNum){
						if(test==7||test==1)
							myprintf("Nurse [%d] tells Parent [%d] \"Shot is over.\"\n", arg2, 2);
					}
					else{
						if(test==7)
							myprintf("Nurse [%d] tells Adult Patient [%d] \"Shot is over.\"\n", arg2, 2);                                     
					}
					myLocalSheet->shotOrNot = 1;
					myLocalSheet->state = 6;
					SignalCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
					WaitCondition(patientCV[myLocalSheet->id], patientLock[myLocalSheet->id]);
					ReleaseLock(patientLock[myLocalSheet->id]);
				case 2:
				case 6:
					AcquireLock(examineRoomPatientLock[examineRoomId]);
					/* Tell patient to follow*/
					patientneedto[myLocalSheet->id] = 6;
					/* Take the patient to the cashier*/
					if (myLocalSheet->id < childNum){
						SignalCondition(examineRoomPatientCV[examineRoomId], examineRoomPatientLock[examineRoomId]);
						WaitCondition(examineRoomPatientCV[examineRoomId], examineRoomPatientLock[examineRoomId]);
						if(test==7||test==4||test==1)
							myprintf("Nurse [%d] escorts Parent [%d] to Cashier.\n", arg2, 2);
					}
					else{
						if(test==7||test==4)
							myprintf("Nurse [%d] escorts Adult Patient [%d] to Cashier.\n", arg2, 2);
					}
					AcquireLock(cashierListLock);
					InQueue(&cashierList, myLocalSheet);		
					SignalCondition(examineRoomPatientCV[examineRoomId], examineRoomPatientLock[examineRoomId]);
					ReleaseLock(examineRoomPatientLock[examineRoomId]);
					/* Release the examine room*/
					ReleaseExamineRoom(examineRoomId);
					/* Hand the sheet to cashier*/
					ReleaseLock(cashierListLock);
					break;
				default:
					break;
			}
		}
		doTask();
	}
	totalNurseNum --;
	Exit(0);
}


void Doctor() {
	struct SheetEntry *myLocalSheet;
	int index;
	int arg1[1];
	int arg2[2];
	int arg3[3];
	int roomNum;
	int result;
	AcquireLock(currentDocLock);
	index = currentDoc++;
	ReleaseLock(currentDocLock);
	arg1[0] = index;
	arg2[0] = index;
	arg3[0] = index;
	
	while (1) {
		/* Stay in the office waiting for nurse's signal
		 After receiving the signal from nurse, doctor start to interact with the patient
		 Get the patient's examination sheet*/
		AcquireLock(doctorLock[index]);
		startSign --;
		AcquireLock(nurseDoctorLock);
		doctorState[index] = 1;
		ReleaseLock(nurseDoctorLock);
		WaitCondition(doctorCV[index], doctorLock[index]);
		if(test==7||test==6)
			myprintf("Doctor [%d] is leaving their office.\n", arg1, 1);
		roomNum = doctorGoRoomId[index];
		AcquireLock(examineRoomPatientLock[roomNum]);
		/* Wake up the patient*/
		myLocalSheet = sheetForDoctor[index];
		doctorInRoom[roomNum] = index;
		SignalCondition(examineRoomPatientCV[roomNum], examineRoomPatientLock[roomNum]);
		ReleaseLock(examineRoomPatientLock[roomNum]);
		WaitCondition(doctorCV[index], doctorLock[index]);
		arg2[1] = roomNum;
		arg3[1] = myLocalSheet->id;
		arg3[2] = roomNum;
		if (myLocalSheet->state == 1){
			/* First time interact with the doctor
			 Start examination*/
			if (myLocalSheet->id < childNum){
				if(test==7||test==6)
					myprintf("Doctor [%d] is reading the examination sheet of Child Patient [%d] in Examination room [%d].\n", arg3, 3);
			}
			else{
				if(test==7||test==6)
					myprintf("Doctor [%d] is reading the examination sheet of Adult Patient [%d] in Examination room [%d].\n",  arg3, 3);                     
			}
			result = ++rand%4;
			switch (result) {
				case 0:
					/* Take Xray*/
					myLocalSheet->state = 3;
					patientneedto[myLocalSheet->id] = 3;
					/* Determin the number*/
					myLocalSheet->imageNum = 1+(++rand)%3;
					if (myLocalSheet->id < childNum){
						if(test==7||test==6)
							myprintf("Doctor [%d] notes down in the sheet that Xray is needed for Child Patient [%d] in Examination room [%d].\n",  arg3, 3);
					}
					else{
						if(test==7||test==6)
							myprintf("Doctor [%d] notes down in the sheet that Xray is needed for Adult Patient [%d] in Examination room [%d].\n",  arg3, 3);                                 
					}
					
					
					/*doctor ask patient to take xray and wait for the patient to come back*/
					break;
				case 1:
					/* Take shot*/
					myLocalSheet->state = 4;
					patientneedto[myLocalSheet->id] = 4;
					if (myLocalSheet->id < childNum){
						if(test==7||test==6)
							myprintf("Doctor [%d] notes down in the sheet that Child Patient [%d] needs to be given a shot in Examination room [%d].\n", arg3, 3);                                     
					}
					else{
						if(test==7||test==6)
							myprintf("Doctor [%d] notes down in the sheet that Adult Patient [%d] needs to be given a shot in Examination room [%d].\n", arg3, 3);                                                                           
					}
					
					break;
					
				default:
					/* Fine*/
					if (myLocalSheet->id < childNum){
						if(test==7||test==6)
							myprintf("Doctor [%d] diagnoses Child Patient [%d] to be fine and is leaving the Examination room [%d].\n", arg3, 3);
					}
					else{
						if(test==7||test==6)
							myprintf("Doctor [%d] diagnoses Adult Patient [%d] to be fine and is leaving the Examination room [%d].\n", arg3, 3);                                    
					}
					myLocalSheet->state = 2;                                      
			}
		}   
		else if (myLocalSheet->state == 5){ 
			result = ++rand%4;      
			if(test==7||test==6)           
				myprintf("Doctor [%d] is examining the Xrays of [Adult/Child] Patient [%d] in Examination room [%d].\n", arg3, 3);
			switch (result) {
				case 0:
					/*need shot after xray*/
					myLocalSheet->state = 4;
					patientneedto[myLocalSheet->id] = 4;
					if (myLocalSheet->id < childNum){
						if(test==7||test==6)
							myprintf("Doctor [%d] notes down in the sheet that Child Patient [%d] needs to be given a shot in Examination room [%d].\n", arg3, 3);                                     
					}
					else{
						if(test==7||test==6)
							myprintf("Doctor [%d] notes down in the sheet that Adult Patient [%d] needs to be given a shot in Examination room [%d].\n", arg3, 3);                                                                           
					}
					break;
				default:        
					myLocalSheet->state = 6;     
			}                               
		}
		SignalCondition(doctorCV[index], doctorLock[index]);
		WaitCondition(doctorCV[index], doctorLock[index]);
		AcquireLock(wallPocketLock);
		wallPocket[roomNum] = myLocalSheet;
		ReleaseLock(wallPocketLock);
		if(test==7||test==6)
			myprintf("Doctor [%d] has left Examination Room [%d].\n", arg2, 2);
		ReleaseLock(doctorLock[index]);
		if(test==7||test==6)
			myprintf("Doctor [%d] is going to their office.\n", arg1, 1);
	}
	Exit(0);
}


void Cashier(){
	int patientId;
	int arg1[2];
	int arg3[2];
	int arg2[3];
	int patientMoney;
	struct SheetEntry *myLocalSheet;
	/* Make sure the thread is executed before patient threads*/
	
	/* Work like the waiting room nurse*/
	while (1) {
		/* Check the line*/
		AcquireLock(cashierLineLock);
		startSign --;
		if (cashierLineNum == 0) {
			/* If no patient wait in the line, sleep until patient comes*/
			cashierState = 1;
		}else {
			/*If there are patients in the line signal one patient*/
			SignalCondition(cashierLineCV, cashierLineLock);
			cashierLineNum --;      /* Decrease the number of patients in the line*/
			cashierState = 2;
		}
		AcquireLock(cashierLock);
		ReleaseLock(cashierLineLock);
		WaitCondition(cashierCV, cashierLock);
		AcquireLock(cashierListLock);
		myLocalSheet = (SheetEntry *) DeQueue(&cashierList);
		ReleaseLock(cashierListLock);
		patientMoney = 10;
		if(myLocalSheet->shotOrNot == 1)
			patientMoney += 12;
		if(myLocalSheet->imageNum == 1 || myLocalSheet->imageNum == 2 || myLocalSheet->imageNum == 3)
			patientMoney += (15*myLocalSheet->imageNum);
		patientId = myLocalSheet->id;
		finalMoney[patientId] = patientMoney;
		arg1[0] = patientId;
		arg1[1] = patientMoney;
		arg2[0] = patientId;
		arg3[0] = patientMoney;
		arg3[1] = patientId;
		arg2[1] = patientId;
		arg2[2] = patientMoney;
		if (patientId < childNum){
			if(test==7||test==3||test==1)
				myprintf("Cashier receives the examination sheet for Child Patient [%d] from Parent [%d].\n", arg2, 2);
		}
		else{
			if(test==7||test==3)
				myprintf("Cashier receives the examination sheet from Adult Patient[%d].\n", arg1, 1);          
		}
		/*Wait patient to pay*/
		SignalCondition(cashierCV, cashierLock);
		if (patientId < childNum){
			if(test==7||test==1||test==3)
				myprintf("Cashier reads the examination sheet of Child Patient [%d] and asks Parent [%d] to pay $ %d \n", arg2, 3);
		}
		else{
			if(test==7||test==3)
				myprintf("Cashier reads the examination sheet of Adult Patient [%d] and asks him to pay $ %d\n", arg1, 2);
		}
		WaitCondition(cashierCV, cashierLock);
		if (patientId < childNum){
			if(test==7||test==3||test==1)
				myprintf("Cashier accepts $ %d from Parent [%d].\n", arg3, 2);
		}
		else{
			if(test==7||test==3)
				myprintf("Cashier accepts $ %d from Adult Patient [%d].\n", arg3, 2);                  
		}
		/* Wait for patient leaving*/
		SignalCondition(cashierCV, cashierLock);
		if (patientId < childNum){
			if(test==7||test==3||test==1)
				myprintf("Cashier gives a receipt of $ %d to Parent [%d].\n", arg3, 2);
		}
		else{
			if(test==7||test==3)
				myprintf("Cashier gives a receipt of $ %d to Adult Patient [%d].\n", arg3, 2);
		}
		WaitCondition(cashierCV, cashierLock);
		/* loop*/
		if (totalPatientNum <= 0) {
			break;
		}
		ReleaseLock(cashierLock);
	}
}

void XRayTechnician(){
	int index;
	int i;
	int imageNum;
	int arg[2];
	int result;
	struct SheetEntry *myLocalSheet;
	AcquireLock(currentxRayLock);
	index = currentxRay++;
	ReleaseLock(currentxRayLock);
	arg[0] = index;
	while (1) {
	 	/* Wait until a Nurse brings a Patient
		 Get the patient's exemination sheet*/
		AcquireLock(xRayWaitLineLock[index]);
		startSign --;
		if (xRayWaitLineNum[index] == 0){
			/* If no patient wait in the line, sleep until patient comes*/
			xtechnicianstate[index] = 1;
		}
		else{
			/*If there are patients in the line signal one patient*/
			SignalCondition(xRayWaitLineCV[index], xRayWaitLineLock[index]);
			xRayWaitLineNum[index] --;      /* Decrease the number of patients in the line*/
			xtechnicianstate[index] = 2;
		}
		AcquireLock(xRayLock[index]);
		ReleaseLock(xRayWaitLineLock[index]);
		WaitCondition(xRayCV[index], xRayLock[index]);
		AcquireLock(waitListLock[index]);
		myLocalSheet = (SheetEntry *) DeQueue(&xrayWaitList[index]);
		ReleaseLock(waitListLock[index]);
		imageNum = myLocalSheet->imageNum;
		xtImageNum[index] = imageNum;
		/* Wait for the patient getting onto the table
		 Take images
		 Stay in xray room waiting for nurse's signal
		 After receiving the signal from nurse, xray technician start to interact with the patient
		 Get the patient's examination sheet
		 
		 Patient comes
		 technician take 3 images */
		arg[0] = index;
		arg[1] = myLocalSheet->id;
		if (myLocalSheet->id < childNum){
			if(test==7)
				myprintf("Xray technician [%d] asks Child Patient [%d] to get on the table.\n", arg, 2);
		}
		else{
			if(test==7)
				myprintf("Xray technician [%d] asks Adult Patient [%d] to get on the table.\n", arg, 2);	
		}
		SignalCondition(xRayCV[index], xRayLock[index]);
		WaitCondition(xRayCV[index], xRayLock[index]);
		for (i=0;i < imageNum;i++){
			if (myLocalSheet->id < childNum){
				if(test==7)
					myprintf("Xray Technician [%d] takes an Xray Image of Child Patient [%d].\n", arg, 2);
			}
			else{
				if(test==7)
					myprintf("Xray Technician [%d] takes an Xray Image of Adult Patient [%d].\n", arg, 2);				
			}
			result = ++rand%3;
			switch (result) {
				case 0:
					myLocalSheet->xrayResults[i] = 1;
					if (myLocalSheet->id < childNum){
						if(test==7)
							myprintf("Xray Technician [%d] records nothing on Child Patient [%d] 's examination sheet.\n", arg, 2);
					}
					else{
						if(test==7)
							myprintf("Xray Technician [%d] records nothing on Adult Patient [%d] 's examination sheet.\n", arg, 2);						
					}
					break;
				case 1:
					myLocalSheet->xrayResults[i] = 2;
					if (myLocalSheet->id < childNum){
						if(test==7)
							myprintf("Xray Technician [%d] records break on Child Patient [%d] 's examination sheet.\n", arg, 2);
					}
					else{
						if(test==7)
							myprintf("Xray Technician [%d] records break on Adult Patient [%d] 's examination sheet.\n", arg, 2);						
					}					
					break;
				case 2:
					myLocalSheet->xrayResults[i] = 3;
					if (myLocalSheet->id < childNum){
						if(test==7)
							myprintf("Xray Technician [%d] records compound fracture on Child Patient [%d] 's examination sheet.\n", arg, 2);
					}
					else{
						if(test==7)
							myprintf("Xray Technician [%d] records compound fracture on Adult Patient [%d] 's examination sheet.\n", arg, 2);						
					}							
					break;
			}
			/*printf("xRay technician [%d] wrote image [%d] on patient [%d] sheet\n", index, i, myLocalSheet->id);*/  
			if (i+1 < imageNum) {
				if (myLocalSheet->id < childNum){
					if(test==7)
						myprintf("Xray Technician [%d] asks Child Patient [%d] to move.\n", arg, 2);
				}
				else{
					if(test==7)
						myprintf("Xray Technician [%d] asks Adult Patient [%d] to move.\n", arg, 2);					
				}
				SignalCondition(xRayCV[index], xRayLock[index]);
				WaitCondition(xRayCV[index], xRayLock[index]);
			}
		}
		myLocalSheet->state = 5;
		AcquireLock(finishListLock);
		InQueue(&xrayFinishList, myLocalSheet);
		if (myLocalSheet->id < childNum){
			if(test==7||test==1){
				myprintf("X-ray Technician [%d] tells Parent [%d] to wait in Xray waiting room.\n", arg, 2);
				myprintf("X-ray Technician [%d] puts Parent [%d] in Xray waiting room wall pocket.\n", arg, 2);
			}
		}else{
			if(test==7){
				myprintf("X-ray Technician [%d] tells Adult Patient [%d] to wait in Xray waiting room.\n", arg, 2);
				myprintf("X-ray Technician [%d] puts Adult Patient [%d] in Xray waiting room wall pocket.\n", arg, 2);
			}
			
		}
		SignalCondition(xRayCV[index], xRayLock[index]);
		WaitCondition(xRayCV[index], xRayLock[index]);
		ReleaseLock(xRayLock[index]);
		ReleaseLock(finishListLock);
	}
	Exit(0);
}

void CleanUp(int patientNum){
	int i;
	DestroyLock(currentxRayLock);
	DestroyLock(currentDocLock);
	DestroyLock(currentNurseLock);
	DestroyLock(currentPatientLock);
	DestroyLock(currentChildLock);
	
	DestroyLock(wrnLock);
	DestroyLock(wrnLineLock);
	DestroyCondition(wrnCV);
	DestroyCondition(wrnLineCV);
	
	DestroyLock(cashierLineLock);
	DestroyLock(cashierLock);
	DestroyLock(cashierListLock);
	DestroyCondition(cashierLineCV);
	DestroyCondition(cashierCV);
	
	DestroyLock(cabinetLock);
	DestroyLock(nurseDoctorLock);
	DestroyCondition(nurseWrnLineCV);
	
	/* Examine room*/
	for (i=0; i<MAX_NUM_ROOMS; i++) {
		DestroyLock(examineRoomPatientLock[i]);
		DestroyCondition(examineRoomPatientCV[i]);
	}
	
	/* Xray Technician*/
	DestroyLock(finishListLock);
	for (i=0; i<MAX_NUM_XTECH; i++) {
		DestroyLock(xRayWaitLineLock[i]);
		DestroyCondition(xRayWaitLineCV[i]);
		DestroyLock(xRayLock[i]);
		DestroyCondition(xRayCV[i]);
		DestroyLock(waitListLock[i]);
	}
	
	/* Patient*/
	for (i=0; i<patientNum+childNum; i++) {
		if (i >= childNum) {
			DestroyLock(patientLock[i]);
			DestroyCondition(patientCV[i]);
		}
		else{
			DestroyLock(childLock[i]);
			DestroyCondition(childCV[i]);
			DestroyLock(patientLock[i]);
			DestroyCondition(patientCV[i]);
		}
	}
	
	/* Doctor*/
	for (i=0; i<MAX_NUM_DOCTORS; i++) {
		DestroyLock(doctorLock[i]);
		DestroyCondition(doctorCV[i]);
	}
	
}

void Initialize(int patientNum, int xtechNum, int doctorNum, int examRoomNum) {
	int arg[1];
	int i;
	int j;
	startSign = 0;
	
	arg[0] = doctorNum;
	myprintf("Number of Doctors = [%d]\n", arg, 1);
	arg[0] = totalNurseNum;
	myprintf("Number of Nurses = [%d]\n", arg, 1);
	arg[0] = xtechNum;
	myprintf("Number of XRay Technicians = [%d]\n", arg, 1);
	arg[0] = patientNum;
	myprintf("Number of Adult Patients = [%d]\n", arg, 1);
	arg[0] = childNum;
	myprintf("Number of Parents/Child Patients = [%d]\n", arg, 1);
	arg[0] = examRoomNum;
	myprintf("Number of Examination Rooms = [%d]\n", arg, 1);
	
	currentxRayLock = CreateLock("lock1", 5);
	currentDocLock = CreateLock("lock2", 5);
	currentNurseLock = CreateLock("lock3", 5);
	currentPatientLock = CreateLock("lock4", 5);
	currentChildLock = CreateLock("lock5", 5);
	
	/* Waiting room nurse*/
	wrnState = 1;
	wrnLock = CreateLock("wrnLock", 7);
	wrnCV = CreateCondition("wrnCV", 5);
	wrnLineLock = CreateLock("wrnLineLock", 11);
	wrnLineCV = CreateCondition("wrnLineCV", 9);
	wrnLineNum = 0;
	wrnList.head = wrnList.tail = 0;
	wrnList.number = 0;
	
	/* Cashier*/
	cashierState = 1;
	cashierLineLock = CreateLock("cashierLineLock", 15);
	cashierLineCV = CreateCondition("cashierLineCV", 13);
	cashierLock = CreateLock("cashierLock", 11);
	cashierCV = CreateCondition("cashierCV", 9);
	cashierLineNum = 0;
	cashierListLock = CreateLock("cashierListLock", 15);
	cashierList.head = cashierList.tail = 0;
	cashierList.number = 0;
	
	/* Nurse*/
	cabinetLock = CreateLock("cabinetLock", 11);
	nurseDoctorLock = CreateLock("nurseDoctorLock", 15);
	nurseWrnLineCV = CreateCondition("nurseWrnLineCV", 14);
	nurseWrnCount = 0;
	patientWaitNum = 0;
	
	/* Examine room*/
	wallPocketLock = CreateLock("wallPocketLock", 14);
	for (i=0; i<MAX_NUM_ROOMS; i++) {
		if (i < examRoomNum) {
			examineRoom[i] = 1;
			examineRoomPatientLock[i] = CreateLock("examineRoomPatientLock", 22);
			examineRoomPatientCV[i] = CreateCondition("examineRoomPatientCV", 20);
		}else {
			examineRoom[i] = 3;
			examineRoomPatientLock[i] = -1;
			examineRoomPatientCV[i] = -1;
		}
		wallPocket[i] = 0;
	}
	
	/* Xray Technician*/
	xRayTechNum = xtechNum;
	finishListLock = CreateLock("finishListLock", 14);
	xrayFinishList.head = xrayFinishList.tail = 0;
	xrayFinishList.number = 0;
	for (i=0; i<MAX_NUM_XTECH; i++) {
		if (i < xtechNum) {
			xtechnicianstate[i] = 1;
			xRayWaitLineLock[i] = CreateLock("xRayWaitLineLock", 16);
			xRayWaitLineCV[i] = CreateCondition("xRayWaitLineCV", 14);
			xRayLock[i] = CreateLock("xRayLock", 8);
			xRayCV[i] = CreateCondition("xRayCV", 6);
			waitListLock[i] = CreateLock("waitListLock", 12);
			xrayWaitList[i].head = xrayWaitList[i].tail = 0;
			xrayWaitList[i].number = 0;
		}
		else{
            xtechnicianstate[i] = 3;
			xRayWaitLineLock[i] = -1;
			xRayWaitLineCV[i] = -1;
			xRayLock[i] = -1;
			xRayCV[i] = -1;
			waitListLock[i] = -1;
		}
		xRayWaitLineNum[i] = 0;
	}
	
	/* Patient*/
	totalPatientNum = patientNum+childNum;
	for (i=0; i<patientNum+childNum; i++) {
		if (i < childNum) {
			childLock[i] = CreateLock("childLock", 9);
			childCV[i] = CreateCondition("childCV", 7);
		}
		
		patientLock[i] = CreateLock("patientLock", 11);
		patientCV[i] = CreateCondition("patientCV", 9);
		roomId[i] = -1;
		xtIdWithPatient[i] = -1;
		patientneedto[i] = 1;
		symptomResponse[i] = 2;
		patientWithNurse[i] = -1;
		isChild[i] = 0;
		finalMoney[i] = 0;
	}
	
	/* Doctor*/
	for (i=0; i<MAX_NUM_DOCTORS; i++) {
		if (i < doctorNum) {
			doctorState[i] = 1;
			doctorLock[i] = CreateLock("doctorLock", 10);
			doctorCV[i] = CreateCondition("doctorCV", 8);
		}
		else{
			doctorState[i] = 3;
			doctorLock[i] = -1;
			doctorCV[i] = -1;
		}
	}
}



int main() {
	int flag;
	int i;
	int quit = 0;
	int input;
	int patientNum = 0;
	int examRoomNum = 0;
	int xtechNum = 0;
	int doctorNum = 0;
	int arg[1];
	childNum = 0;	
	totalNurseNum = 0;
	currentxRay = 0;
	currentDoc = 0;
	currentNurse = 0;
	currentPatient = 0;
	currentChild = 0;
	rand = 0;
	
	myprintf("Test guideline:\n", 0, 0);
	myprintf("1. Child Patients are never abandoned by their Parent, nor go anywhere without their Parent.\n", 0, 0);
	myprintf("2. Waiting Room Nurses only talk to one Patient/Parent at a time. \n", 0, 0);
	myprintf("3. Cashiers only talk to one Patient/Parent at a time.\n", 0, 0);
	myprintf("4. Patients/Parents never go anywhere without being escorted by a Nurse.\n", 0, 0);
	myprintf("5. All Patients leave the Doctor's Office. No one stays in the Waiting Room, Examination Room, or Xray Room, forever.\n", 0, 0);
	myprintf("6. Two Doctors never examine the same Patient at the same time.\n", 0, 0);
	myprintf("7. Final Test. \n", 0, 0);
	myprintf("8. Quit. \n", 0, 0);
	myprintf("Please enter the number 1-8 corresponding to the above options:", 0, 0);
	
	input=myscanf();
	if(input==1){
		test = 1;
		totalNurseNum = 2;
		childNum = 3;
		patientNum = 2;
		examRoomNum = 1;
		xtechNum = 1;
		doctorNum = 1;
		
		Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
		
		startSign = 2+doctorNum+xtechNum;
		/* Fork the threads*/
		Fork(WaitingRoomNurse);
		for (i=0; i<xtechNum; i++) {
			Fork(XRayTechnician);
		}
		
		for (i=0; i<totalNurseNum; i++) {
			Fork(Nurse);
		}
		
		for (i=0; i<doctorNum; i++) {
			Fork(Doctor);
		}
		
		for (i=0; i<patientNum+childNum; i++) {
			if (i<childNum) {
				Fork(AdultPatient);
				Fork(ChildPatient);
			}else {
				Fork(AdultPatient);
			}
		}
		Cashier();
		while (totalNurseNum > 0 || totalPatientNum > 0) {
			Yield();
		}
		CleanUp(patientNum);
	}
	else if(input==2){
		test = 2;
		totalNurseNum = 5;
		childNum = 0;
		patientNum = 2;
		examRoomNum = 5;
		xtechNum = 2;
		doctorNum = 3;
		
		Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
		
		startSign = 2+doctorNum+xtechNum;
		/* Fork the threads*/
		Fork(WaitingRoomNurse);
		for (i=0; i<xtechNum; i++) {
			Fork(XRayTechnician);
		}
		
		for (i=0; i<totalNurseNum; i++) {
			Fork(Nurse);
		}
		
		for (i=0; i<doctorNum; i++) {
			Fork(Doctor);
		}
		
		for (i=0; i<patientNum+childNum; i++) {
			if (i<childNum) {
				Fork(AdultPatient);
				Fork(ChildPatient);
			}else {
				Fork(AdultPatient);
			}
		}
		Cashier();
		while (totalNurseNum > 0 || totalPatientNum > 0) {
			Yield();
		}
		CleanUp(patientNum);
	}
	else if(input==3){
		test = 3;
		totalNurseNum = 2;
		childNum = 1;
		patientNum = 2;
		examRoomNum = 2;
		xtechNum = 1;
		doctorNum = 2;
		
		Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
		
		startSign = 2+doctorNum+xtechNum;
		/* Fork the threads*/
		Fork(WaitingRoomNurse);
		for (i=0; i<xtechNum; i++) {
			Fork(XRayTechnician);
		}
		
		for (i=0; i<totalNurseNum; i++) {
			Fork(Nurse);
		}
		
		for (i=0; i<doctorNum; i++) {
			Fork(Doctor);
		}
		
		for (i=0; i<patientNum+childNum; i++) {
			if (i<childNum) {
				Fork(AdultPatient);
				Fork(ChildPatient);
			}else {
				Fork(AdultPatient);
			}
		}
		Cashier();
		while (totalNurseNum > 0 || totalPatientNum > 0) {
			Yield();
		}
		CleanUp(patientNum);
	}
	else if(input==4){
		test = 4;
		totalNurseNum = 2;
		childNum = 2;
		patientNum = 2;
		examRoomNum = 2;
		xtechNum = 1;
		doctorNum = 2;
		
		Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
		
		startSign = 2+doctorNum+xtechNum;
		/* Fork the threads*/
		Fork(WaitingRoomNurse);
		for (i=0; i<xtechNum; i++) {
			Fork(XRayTechnician);
		}
		
		for (i=0; i<totalNurseNum; i++) {
			Fork(Nurse);
		}
		
		for (i=0; i<doctorNum; i++) {
			Fork(Doctor);
		}
		
		for (i=0; i<patientNum+childNum; i++) {
			if (i<childNum) {
				Fork(AdultPatient);
				Fork(ChildPatient);
			}else {
				Fork(AdultPatient);
			}
		}
		Cashier();
		while (totalNurseNum > 0 || totalPatientNum > 0) {
			Yield();
		}
		CleanUp(patientNum);
	}
	else if(input==5){
		test = 5;
		totalNurseNum = 2;
		childNum = 1;
		patientNum = 2;
		examRoomNum = 2;
		xtechNum = 1;
		doctorNum = 2;
		
		Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
		
		startSign = 2+doctorNum+xtechNum;
		/* Fork the threads*/
		Fork(WaitingRoomNurse);
		for (i=0; i<xtechNum; i++) {
			Fork(XRayTechnician);
		}
		
		for (i=0; i<totalNurseNum; i++) {
			Fork(Nurse);
		}
		
		for (i=0; i<doctorNum; i++) {
			Fork(Doctor);
		}
		
		for (i=0; i<patientNum+childNum; i++) {
			if (i<childNum) {
				Fork(AdultPatient);
				Fork(ChildPatient);
			}else {
				Fork(AdultPatient);
			}
		}
		Cashier();
		while (totalNurseNum > 0 || totalPatientNum > 0) {
			Yield();
		}
		CleanUp(patientNum);
	}
	else if(input==6){
		test = 6;
		totalNurseNum = 2;
		childNum = 1;
		patientNum = 2;
		examRoomNum = 2;
		xtechNum = 1;
		doctorNum = 2;
		
		Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
		
		startSign = 2+doctorNum+xtechNum;
		/* Fork the threads*/
		Fork(WaitingRoomNurse);
		for (i=0; i<xtechNum; i++) {
			Fork(XRayTechnician);
		}
		
		for (i=0; i<totalNurseNum; i++) {
			Fork(Nurse);
		}
		
		for (i=0; i<doctorNum; i++) {
			Fork(Doctor);
		}
		
		for (i=0; i<patientNum+childNum; i++) {
			if (i<childNum) {
				Fork(AdultPatient);
				Fork(ChildPatient);
			}else {
				Fork(AdultPatient);
			}
		}
		Cashier();
		while (totalNurseNum > 0 || totalPatientNum > 0) {
			Yield();
		}
		CleanUp(patientNum);
	}
	else if(input==7){
		test = 7;
		myprintf("Enter the test data:\n", 0, 0);
		myprintf("Number of Doctors (2 to 3): = \n", 0, 0);
		doctorNum = myscanf();
		if (doctorNum < 2 || doctorNum > 3){
			myprintf("The number of doctor must be 2 or 3!\n", 0, 0);
		}
		else{
			myprintf("Number of Nurses (2 - 5) = \n", 0, 0);
			totalNurseNum = myscanf();
			if (totalNurseNum < 2 || totalNurseNum > 5){
				myprintf("The number of Nurse must between 2 and 5!\n", 0, 0);
			}
			else{
				myprintf("Number of XRay Technicians/Rooms (1 - 2) = \n", 0, 0);
				xtechNum = myscanf();
				if (xtechNum < 1 || xtechNum >2){
					myprintf("The number of XRay Technicians must be 1 and 2!\n", 0, 0);
				}
				else{
					myprintf("Number of Parents/Child Patients (max 50) = \n", 0, 0);
					childNum = myscanf();
					if (childNum < 0){
						myprintf("The number of Child Patients must greater than 0!\n", 0, 0);
					}
					else{
						myprintf("Number of Adult Patients (max 50) = \n", 0, 0);
						patientNum = myscanf();
						if (patientNum < 0) {
							myprintf("The number of Adult Patients must greater than 0!\n", 0, 0);
						}else {
							myprintf("Number of Examination Rooms (2 - 5) = \n", 0, 0);
							examRoomNum = myscanf();
							if (examRoomNum < 2 || examRoomNum > 5){
								myprintf("The number of Examination Rooms must between 2 and 5!\n", 0, 0);
							}else {
								Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
								
								startSign = 2+doctorNum+xtechNum;
								/* Fork the threads*/
								Fork(WaitingRoomNurse);
								for (i=0; i<xtechNum; i++) {
									Fork(XRayTechnician);
								}
								
								for (i=0; i<totalNurseNum; i++) {
									Fork(Nurse);
								}
								
								for (i=0; i<doctorNum; i++) {
									Fork(Doctor);
								}
								
								for (i=0; i<patientNum+childNum; i++) {
									if (i<childNum) {
										Fork(AdultPatient);
										Fork(ChildPatient);
									}else {
										Fork(AdultPatient);
									}
								}
								Cashier();
								while (totalNurseNum > 0 || totalPatientNum > 0) {
									Yield();
								}
								CleanUp(patientNum);
							}
						}
					}
				}
			}
		}
	}
	else if (input == 8){
		quit = 1;;
	}
	else{
		myprintf("There is no option of your input.\n", 0, 0);
	}
	return 0;
}
